﻿Imports System.Net
Imports System.Net.sockets
Imports System.Threading

Public Class ServerSocket

    Protected _serverSocket As Socket                 '服务器Socket
    Protected _maxClient As Integer = 100             '最大连接数
    Protected _clientList As List(Of ClientInfo)      '客户端Socket列表
    Protected _curClientCount As Integer = 0          '当前客户端连接数
    Protected _acceptThread As Thread                 '接收连接线程
    Protected _isAccept As Boolean                    '是否接收连接
    Protected _isReceive As Boolean                   '是否接收数据
    'Protected _receiveThread As Thread                '接收数据线程
    Protected _heartIdleTime As Integer               '心跳包接受发送时间
    Protected _heartWaitTime As Integer               '心跳包接受等待服务器响应间隔
    Protected _heartRep As Integer                    '等待服务器次数
    Protected _heartDataClient() As Byte = Text.Encoding.ASCII.GetBytes("Hearting") '客户端心跳包数据
    Protected _heartDataServer() As Byte = _heartDataClient '服务端心跳包数据
    Protected _receiveBufferSize As Integer = 512
    Protected _sendBufferSize As Integer = 512
    Protected _receiveTimeout As Integer = 0
    Protected _sendTimeout As Integer = 0


    Public Event OnAccept As EventHandler(Of AcceptEventArgs)
    Public Event OnMaxClient As EventHandler
    Public Event OnReceive As EventHandler(Of ReceiveEventArgs)
    Public Event OnClientDisconnect As EventHandler(Of DisconnectArgs)
    Public Event OnFreeTime As EventHandler
    Public Event OnHeartTimeout As EventHandler


#Region "Properties"
    ''' <summary>
    ''' 服务器端Socket对象
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Socket() As Socket
        Get
            Return _serverSocket
        End Get
    End Property
    ''' <summary>
    ''' 数据接收缓冲区大小(字节)。默认512字节。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property ReceiveBufferSize() As Integer
        Get
            Return _receiveBufferSize
        End Get
        Set(ByVal value As Integer)
            _receiveBufferSize = value
        End Set
    End Property

    ''' <summary>
    ''' 数据发送缓冲区大小(字节)。默认512字节。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property SendBufferSize() As Integer
        Get
            Return _sendBufferSize
        End Get
        Set(ByVal value As Integer)
            _sendBufferSize = value
        End Set
    End Property

    ''' <summary>
    ''' 数据接收超时值(毫秒)。默认值为 0，指示超时期限无限大。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property ReceiveTimeout() As Integer
        Get
            Return _receiveTimeout
        End Get
        Set(ByVal value As Integer)
            _receiveTimeout = value
        End Set
    End Property

    ''' <summary>
    ''' 数据发送超时值(毫秒)。默认值为 0，指示超时期限无限大。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property SendTimeout() As Integer
        Get
            Return _sendTimeout
        End Get
        Set(ByVal value As Integer)
            _sendTimeout = value
        End Set
    End Property
    ''' <summary>
    ''' 客户端信息集合
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property ClientList() As List(Of ClientInfo)
        Get
            Return _clientList
        End Get
    End Property

    ''' <summary>
    ''' 服务器最大连接数。默认为100
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property MaxClientCount() As Integer
        Get
            Return _maxClient
        End Get
        Set(ByVal value As Integer)
            _maxClient = value
        End Set
    End Property

    ''' <summary>
    ''' 服务器当前连接数
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property CurrentClientCount() As Integer
        Get
            Return _curClientCount
        End Get
    End Property
    ''' <summary>
    ''' 心跳包开始发送时间(毫秒)
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property HeartIdleTime() As Integer
        Get
            Return _heartIdleTime / 10000
        End Get
        Set(ByVal value As Integer)
            _heartIdleTime = value * 10000
        End Set
    End Property

    ''' <summary>
    ''' 心跳包发送等待响应间隔(毫秒)
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property HeartWaitTime() As Integer
        Get
            Return _heartWaitTime / 10000
        End Get
        Set(ByVal value As Integer)
            _heartWaitTime = value * 10000
        End Set
    End Property

    ''' <summary>
    ''' 等待心跳包响应次数
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property HeartRep() As Integer
        Get
            Return _heartRep
        End Get
        Set(ByVal value As Integer)
            _heartRep = value
        End Set
    End Property

    ''' <summary>
    ''' 服务器端心跳包数据
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property HeartDataServer() As Byte()
        Get
            Return _heartDataServer
        End Get
        Set(ByVal value As Byte())
            _heartDataServer = value
        End Set
    End Property

    ''' <summary>
    ''' 客户端心跳包数据
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property HeartDataClient() As Byte()
        Get
            Return _heartDataClient
        End Get
        Set(ByVal value As Byte())
            _heartDataClient = value
        End Set
    End Property
#End Region

    Public Sub New()
        _serverSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        _clientList = New List(Of ClientInfo)
    End Sub


    ''' <summary>
    ''' 开启服务器
    ''' </summary>
    ''' <param name="port">服务器端口</param>
    ''' <param name="maxClient">最大客户端连接数</param>
    ''' <param name="backlog">挂起连接队列的最大长度</param>
    ''' <remarks></remarks>
    Public Function ServerStart(ByVal port As Integer, ByVal maxClient As Integer, ByVal backlog As Integer) As Boolean
        Dim ipep As New IPEndPoint(IPAddress.Any, port)

        Try
            _maxClient = maxClient

            _serverSocket.Bind(ipep)
            _serverSocket.Listen(backlog)

            _curClientCount = 0
            For i As Integer = 0 To _maxClient - 1
                Dim client As New ClientInfo()
                client.ServerSocket = Me
                AddHandler client.OnReceive, AddressOf ReceiveMethod
                AddHandler client.OnClientDisconnect, AddressOf DisconnectMethod
                AddHandler client.OnFreeTime, AddressOf FreeTimeMethod
                AddHandler client.OnHeartTimeout, AddressOf HeartTimeoutMethod
                _clientList.Add(client)
            Next

            '开始接收连接
            If _acceptThread Is Nothing Then
                _acceptThread = New Thread(AddressOf AcceptMethod)
                _acceptThread.IsBackground = True
                _isAccept = True
                _acceptThread.Start()
            End If

        Catch ex As Exception
            Return False
        End Try

        Return True
    End Function

    '停止服务器
    Protected Function ServerStop() As Boolean
        Try
            _isAccept = False
            If _acceptThread IsNot Nothing Then
                _acceptThread.Abort()
                _acceptThread = Nothing
            End If

        Catch ex As Exception
            Return False
        End Try

        Return True
    End Function

    '接收连接线程方法
    Protected Sub AcceptMethod()
        Try
            Do While _isAccept

                'If _clientList.Count < _maxClient Then '判断最大连接数
                Dim clientSocket As Socket = _serverSocket.Accept()
                Dim client As ClientInfo = Nothing

                For Each c As ClientInfo In _clientList
                    If c.M_Socket Is Nothing Then
                        c.M_Socket = clientSocket
                        client = c
                        System.Threading.Interlocked.Increment(_curClientCount)
                        Exit For
                    End If
                Next

                If client Is Nothing Then
                    RaiseEvent OnMaxClient(Me, EventArgs.Empty)
                    Thread.Sleep(1000)
                    Continue Do
                End If

                'Dim client As New ClientInfo(clientSocket)
                clientSocket.ReceiveBufferSize = _receiveBufferSize
                clientSocket.SendBufferSize = _sendBufferSize
                clientSocket.ReceiveTimeout = _receiveTimeout
                clientSocket.SendTimeout = _sendTimeout
                'client.ServerSocket = Me
                'AddHandler client.OnReceive, AddressOf ReceiveMethod
                'AddHandler client.OnClientDisconnect, AddressOf DisconnectMethod

                '_clientList.Add(client)

                client.StartWork()

                Try
                    Dim ae As New AcceptEventArgs()
                    ae.Client = client
                    ae.RemoteEndPoint = clientSocket.RemoteEndPoint
                    RaiseEvent OnAccept(Me, ae)
                Catch ex As Exception

                End Try

                'Else
                ''Dim client As Socket = _serverSocket.Accept()
                ''client.Shutdown(SocketShutdown.Both)
                ''client.Close()
                'RaiseEvent OnMaxClient(Me, EventArgs.Empty)
                'Thread.Sleep(1000)
                'End If
            Loop
        Catch ex As SocketException
            Throw ex
        End Try
    End Sub

    ''' <summary>
    ''' 发送数据至客户端
    ''' </summary>
    ''' <param name="bytes">要发送的数据</param>
    ''' <param name="client">目标客户端对象</param>
    ''' <returns>返回已发送数据的长度(字节)</returns>
    ''' <remarks></remarks>
    Public Function SendToClient(ByVal bytes() As Byte, ByVal client As ClientInfo) As Integer
        Return client.Send(bytes)
    End Function

    ''' <summary>
    ''' 发送数据至客户端
    ''' </summary>
    ''' <param name="bytes">要发送的数据</param>
    ''' <param name="length">要发送的数据长度(字节)</param>
    ''' <param name="client">目标客户端对象</param>
    ''' <returns>返回已发送数据的长度(字节)</returns>
    ''' <remarks></remarks>
    Public Function SendToClient(ByVal bytes() As Byte, ByVal length As Integer, ByVal client As ClientInfo) As Integer
        Return client.Send(bytes, length)
    End Function

    ''' <summary>
    ''' 从客户端读取接收数据
    ''' </summary>
    ''' <param name="length">读取长度(字节)</param>
    ''' <param name="client">目标客户端对象</param>
    ''' <returns>返回byte数组</returns>
    ''' <remarks></remarks>
    Public Function ReceiveFromClient(ByVal length As Integer, ByVal client As ClientInfo) As Byte()
        Return client.Receive(length)
    End Function

    '事件处理方法
    Protected Sub ReceiveMethod(ByVal sender As Object, ByVal e As ReceiveEventArgs)
        RaiseEvent OnReceive(sender, e)
    End Sub
    Protected Sub DisconnectMethod(ByVal sender As Object, ByVal e As DisconnectArgs)
        RaiseEvent OnClientDisconnect(sender, e)
    End Sub
    Protected Sub FreeTimeMethod(ByVal sender As Object, ByVal e As EventArgs)
        RaiseEvent OnFreeTime(sender, e)
    End Sub
    Protected Sub HeartTimeoutMethod(ByVal sender As Object, ByVal e As EventArgs)
        RaiseEvent OnHeartTimeout(sender, e)
    End Sub

    ''' <summary>
    ''' 关闭所有客户端连接
    ''' </summary>
    ''' <param name="timeout">等待 timeout 秒以发送所有剩余数据，然后关闭该套接字。</param>
    ''' <remarks></remarks>
    Public Sub CloseAll(ByVal timeout As Integer)
        Try
            For Each client As ClientInfo In _clientList
                client.Close(timeout)
                RemoveHandler client.OnReceive, AddressOf ReceiveMethod
                RemoveHandler client.OnClientDisconnect, AddressOf DisconnectMethod
            Next
            _clientList.Clear()
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    ''' <summary>
    ''' 关闭指定客户端连接
    ''' </summary>
    ''' <param name="timeout">等待 timeout 秒以发送所有剩余数据，然后关闭该套接字。</param>
    ''' <remarks></remarks>
    Public Sub CloseClient(ByVal timeout As Integer, ByVal client As ClientInfo)
        Monitor.Enter(Me)
        Try
            'System.IO.File.AppendAllText(".\\" & Now.Month & Now.Day & ".log", "Close Client" & vbCrLf)
            System.Threading.Interlocked.Decrement(_curClientCount)
            client.Close(timeout)
            'RemoveHandler client.OnReceive, AddressOf ReceiveMethod
            'RemoveHandler client.OnClientDisconnect, AddressOf DisconnectMethod
            '_clientList.Remove(client)

            'System.GC.Collect()
        Catch ex As Exception
            Throw ex
        Finally
            Monitor.Exit(Me)
        End Try
    End Sub

    ''' <summary>
    ''' 关闭服务器Socket连接并释放所有关联的资源
    ''' </summary>
    ''' <param name="timeout">等待 timeout 秒以发送所有剩余数据，然后关闭该套接字。</param>
    ''' <remarks></remarks>
    Public Sub Close(ByVal timeout As Integer)
        'System.IO.File.AppendAllText(".\\" & Now.Month & Now.Day & ".log", "Close Server" & vbCrLf)
        Try
            ServerStop()
            CloseAll(0)
            _serverSocket.Close(timeout)
            _serverSocket = Nothing
            _clientList = Nothing
        Catch ex As Exception
            Throw ex
        End Try

        GC.Collect()
    End Sub


End Class

Public Enum ClientListHandlers
    ADD
    REMOVE
End Enum


''' <summary>
''' 客户端信息类
''' </summary>
''' <remarks></remarks>
Public Class ClientInfo

    'Protected _ID As String
    Protected _socket As Socket
    Protected _thread As Thread
    Protected _isReceiving As Boolean
    Protected _serverSocket As ServerSocket
    Protected _buffer() As Byte
    Protected _isDisconnected As Boolean = True
    Protected _isFreeTime As Boolean = False
    Protected _lastTicks As Long
    Protected _freeTicks As Long
    Protected _heartData() As Byte
    'Protected _heartCallback As New AsyncCallback(AddressOf HeartCallback)

    Public Event OnReceive As EventHandler(Of ReceiveEventArgs)
    Public Event OnClientDisconnect As EventHandler(Of DisconnectArgs)
    Public Event OnFreeTime As EventHandler
    Public Event OnHeartTimeout As EventHandler

#Region "Properties"

    'Public ReadOnly Property ID() As String
    '    Get
    '        Return _ID
    '    End Get
    'End Property

    Friend Property M_Socket() As Socket
        Get
            Return _Socket
        End Get
        Set(ByVal value As Socket)
            _socket = value
        End Set
    End Property

    Public ReadOnly Property Socket() As Socket
        Get
            Return _socket
        End Get
        'Set(ByVal value As Socket)
        '    _socket = value
        'End Set
    End Property

    Public Property ServerSocket() As ServerSocket
        Get
            Return _serverSocket
        End Get
        Set(ByVal value As ServerSocket)
            _serverSocket = value
        End Set
    End Property

    Public Property IsDisconnected() As Boolean
        Get
            Return _isDisconnected
        End Get
        Set(ByVal value As Boolean)
            _isDisconnected = value
        End Set
    End Property

    ''' <summary>
    ''' 是否空闲状态
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property IsFreeTime() As Boolean
        Get
            Return _isFreeTime
        End Get
        Set(ByVal value As Boolean)
            _isFreeTime = value
        End Set
    End Property

    ''' <summary>
    ''' 最后操作时刻
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property LastTicks() As Long
        Get
            Return _lastTicks
        End Get
        Set(ByVal value As Long)
            _lastTicks = value
        End Set
    End Property

    ''' <summary>
    ''' 空闲时刻
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property FreeTicks() As Long
        Get
            Return _freeTicks
        End Get
        Set(ByVal value As Long)
            _freeTicks = value
        End Set
    End Property

    'Public Property HeartDataClient() As Byte()
    '    Get
    '        Return _heartDataClient
    '    End Get
    '    Set(ByVal value As Byte())
    '        _heartDataClient = value
    '        ReDim _heartData(value.Length - 1)
    '    End Set
    'End Property

    'Public Property HeartDataServer() As Byte()
    '    Get
    '        Return _heartDataServer
    '    End Get
    '    Set(ByVal value As Byte())
    '        _heartDataServer = value
    '    End Set
    'End Property

#End Region

    Public Sub New()

    End Sub
    Public Sub New(ByVal clientSocket As Socket)
        '_ID = System.Guid.NewGuid().ToString()
        _socket = clientSocket
        '_isDisconnected = False
    End Sub

    Friend Sub StartWork()
        If _thread Is Nothing Then
            _thread = New Thread(AddressOf WorkerThread)
            _isReceiving = True
            _isDisconnected = False
            _isFreeTime = False
            _thread.IsBackground = True
            _thread.Start()
        End If
    End Sub

    '接收数据工作线程方法
    Protected Sub WorkerThread(ByVal state As Object)
        Dim bufLen As Integer = 0
        Dim nowTicks As Long = 0
        _lastTicks = DateTime.Now.Ticks

        Do While _isReceiving

            Try
                nowTicks = DateTime.Now.Ticks
                Dim clientSocket As Socket = _socket

                '检测客户端空闲状态
                If _isFreeTime Then
                    Do While (nowTicks - _freeTicks) < ServerSocket.HeartWaitTime * 10000 * ServerSocket.HeartRep
                        If Not _isFreeTime Then Exit Do
                        nowTicks = DateTime.Now.Ticks
                        BeginHeart()
                        If _isDisconnected Then Exit Do
                        Thread.Sleep(100)
                    Loop

                    If _isFreeTime Then
                        If _isDisconnected = False Then RaiseEvent OnHeartTimeout(Me, EventArgs.Empty)
                        If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.HeartTimeout))
                    End If

                    'If (nowTicks - _freeTicks) > ServerSocket.HeartWaitTime * 10000 * ServerSocket.HeartRep Then
                    '    RaiseEvent OnHeartTimeout(Me, EventArgs.Empty)
                    '    If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.HeartTimeout))
                    '    Exit Do
                    'End If

                    'BeginHeart()
                    'If _isDisconnected Then Exit Do
                Else

                    '检测客户端Socket是否有数据
                    Try
                        If clientSocket.Poll(0, SelectMode.SelectRead) Then
                            bufLen = clientSocket.Available
                            If bufLen = 0 Then
                                If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
                                Exit Do
                            Else
                                _isFreeTime = False
                                _lastTicks = DateTime.Now.Ticks
                                If _isDisconnected = False Then RaiseEvent OnReceive(Me, New ReceiveEventArgs(bufLen))
                            End If
                        Else
                            '检测客户端空闲状态
                            Try
                                If (nowTicks - _lastTicks) > (ServerSocket.HeartIdleTime * 10000) Then
                                    If _isFreeTime = False Then
                                        _freeTicks = DateTime.Now.Ticks
                                        _isFreeTime = True
                                        'BeginHeart()
                                        If _isDisconnected = False Then RaiseEvent OnFreeTime(Me, EventArgs.Empty)
                                    End If
                                Else
                                    _isFreeTime = False
                                End If
                            Catch ex As ObjectDisposedException

                            Catch ex As NullReferenceException

                            Catch ex As Exception
                                'Throw ex
                            End Try
                        End If
                    Catch ex As SocketException
                        'socketException(ex.SocketErrorCode)
                    Catch ex As ObjectDisposedException
                        Exit Do
                    Catch ex As Exception
                        'Throw ex
                    End Try

                End If

                ''检测客户端空闲状态
                'Try
                '    If (nowTicks - _lastTicks) > (ServerSocket.HeartIdleTime) Then
                '        If _isFreeTime = False Then
                '            _freeTicks = DateTime.Now.Ticks
                '            _isFreeTime = True
                '            BeginHeart()
                '            'RaiseEvent OnFreeTime(client, EventArgs.Empty)
                '        End If
                '    Else
                '        _isFreeTime = False
                '    End If
                'Catch ex As ObjectDisposedException

                'Catch ex As NullReferenceException

                'Catch ex As Exception
                '    Throw ex
                'End Try

            Catch ex As SocketException
                'socketException(ex.SocketErrorCode)
            Catch ex As ThreadAbortException
                Exit Do
                'Catch ex As Exception
                '    'Throw ex
            End Try

            Thread.Sleep(100)
        Loop

    End Sub

    'Protected Sub DisconnectEventCallback(ByVal state As Object)
    '    RaiseEvent OnClientDisconnect(Me, state)
    'End Sub


    ''' <summary>
    ''' 发送数据至客户端
    ''' </summary>
    ''' <param name="bytes">要发送的数据</param>
    ''' <returns>返回已发送数据的长度(字节)</returns>
    ''' <remarks></remarks>
    Public Function Send(ByVal bytes() As Byte) As Integer
        If bytes Is Nothing Then Return -1
        Send = 0

        Try

            Send = _socket.Send(bytes, SocketFlags.None)
            If Send = 0 Then
                If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
                Return -1
            End If
        Catch ex As SocketException
            If ex.SocketErrorCode = SocketError.TimedOut Then
                Return -1
            End If
            socketException(ex.SocketErrorCode)
        Catch ex As ObjectDisposedException
            Return -1
        Catch ex As Exception
            Throw ex
        Finally
            _isFreeTime = False
            _lastTicks = DateTime.Now.Ticks
        End Try

    End Function
    ''' <summary>
    ''' 发送数据至客户端
    ''' </summary>
    ''' <param name="bytes">要发送的数据</param>
    ''' <param name="length">要发送的数据长度(字节)</param>
    ''' <returns>返回已发送数据的长度(字节)</returns>
    ''' <remarks></remarks>
    Public Function Send(ByVal bytes() As Byte, ByVal length As Integer) As Integer
        If bytes Is Nothing Then Return -1
        Send = 0

        Try

            Send = _socket.Send(bytes, length, SocketFlags.None)
            If Send = 0 Then
                If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
                Return -1
            End If
        Catch ex As SocketException
            If ex.SocketErrorCode = SocketError.TimedOut Then
                Return -1
            End If
            socketException(ex.SocketErrorCode)
        Catch ex As ObjectDisposedException
            Return -1
        Catch ex As Exception
            Throw ex
        Finally
            _isFreeTime = False
            _lastTicks = DateTime.Now.Ticks
        End Try

    End Function

    ''' <summary>
    ''' 从客户端读取接收数据
    ''' </summary>
    ''' <param name="length">读取长度(字节)</param>
    ''' <returns>返回byte数组</returns>
    ''' <remarks></remarks>
    Public Function Receive(ByVal length As Integer) As Byte()
        ReDim _buffer(length - 1)

        Try
            If _socket.Receive(_buffer, 0, length, SocketFlags.None) = 0 Then
                If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
                _buffer = Nothing
            End If

        Catch ex As SocketException
            socketException(ex.SocketErrorCode)
            _buffer = Nothing
        Catch ex As ObjectDisposedException
            _buffer = Nothing
        Catch ex As Exception
            _buffer = Nothing
            Throw ex
        Finally
            _isFreeTime = False
            _lastTicks = DateTime.Now.Ticks
        End Try

        Return _buffer
    End Function

#Region "Not Use"

    'Protected Sub BeginHeart()
    '    Try
    '        ReDim _heartData(_serverSocket.HeartDataClient.Length - 1)
    '        _socket.BeginReceive(_heartData, 0, _heartData.Length, SocketFlags.None, _heartCallback, Nothing)
    '    Catch ex As Exception

    '    End Try
    'End Sub

    'Protected Sub HeartCallback(ByVal ar As IAsyncResult)
    '    If ar.IsCompleted Then
    '        Dim length As Integer = 0

    '        Try
    '            length = _socket.EndReceive(ar)
    '            If length = 0 Then
    '                If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
    '                Exit Try
    '            End If

    '            _isFreeTime = False
    '            _lastTicks = DateTime.Now.Ticks

    '            If CheckHeart(_heartData) Then
    '                length = _socket.Send(_serverSocket.HeartDataServer, SocketFlags.None)
    '                If length = 0 Then
    '                    If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
    '                    Exit Try
    '                End If
    '            Else
    '                _buffer = _heartData
    '                RaiseEvent OnReceive(Me, New ReceiveEventArgs(_buffer.Length))
    '            End If
    '        Catch ex As NullReferenceException

    '        Catch ex As ObjectDisposedException

    '        Catch ex As SocketException
    '            socketException(ex.SocketErrorCode)
    '        Catch ex As Exception
    '            Throw ex
    '        End Try

    '    End If

    'End Sub
#End Region

    Protected Sub BeginHeart()
        Dim length As Integer = 0
        ReDim _heartData(_serverSocket.HeartDataClient.Length - 1)

        Try
            length = _socket.Receive(_heartData, _heartData.Length, SocketFlags.None)
            If length = 0 Then
                If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
                Return
            End If

            _isFreeTime = False
            _lastTicks = DateTime.Now.Ticks

            If CheckHeart(_heartData) Then
                length = _socket.Send(_serverSocket.HeartDataServer, SocketFlags.None)
                If length = 0 Then
                    If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Normal))
                    Return
                End If
            Else
                _buffer = _heartData
                If _isDisconnected = False Then RaiseEvent OnReceive(Me, New ReceiveEventArgs(_buffer.Length))
            End If
        Catch ex As NullReferenceException

        Catch ex As ObjectDisposedException

        Catch ex As SocketException
            socketException(ex.SocketErrorCode)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub


#Region "Heart Beat Functions"

    Protected Function CheckHeart(ByVal bytes() As Byte) As Boolean
        If bytes.Length = _serverSocket.HeartDataClient.Length Then
            For i As Integer = 0 To bytes.Length - 1
                If bytes(i) <> _serverSocket.HeartDataClient(i) Then
                    Return False
                End If
            Next i
            Return True
        End If
        Return False
    End Function

#End Region

    Friend Sub Close(ByVal timeout As Integer)
        If _isDisconnected Then Return
        'Monitor.Enter(Me)
        Try
            _isDisconnected = True

            _isReceiving = False
            If _thread IsNot Nothing Then
                '_thread.Abort()
                _thread = Nothing
            End If

            _socket.Shutdown(SocketShutdown.Both)
            _socket.Close(timeout)
            _socket = Nothing
        Catch ex As SocketException
            socketException(ex.SocketErrorCode)
        Catch ex As Exception
            Throw ex
        Finally
            'Monitor.Exit(Me)
        End Try
    End Sub

    Protected Sub socketException(ByVal errorCode As SocketError)
        'Monitor.Enter(Me)
        Try
            Select Case errorCode
                Case SocketError.ConnectionReset
                    If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.ConnectionReset))
                Case SocketError.ConnectionAborted
                    If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.ConnectionAborted))
                    'Me.m_serverSocket.CloseClient(0, Me)
                Case SocketError.Shutdown
                    If _isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.Shutdown))
                Case SocketError.TimedOut
                    'If m_isDisconnected = False Then RaiseEvent OnClientDisconnect(Me, New DisconnectArgs(DisconnectType.TimedOut))
                Case SocketError.HostUnreachable '网卡禁用
                    'RaiseEvent OnHostUnreachable(Me, EventArgs.Empty)
                Case SocketError.WouldBlock

                Case SocketError.NotSocket

                Case SocketError.AddressAlreadyInUse
                    'Me.Close(0)
                    'Throw New AppException("AddressAlreadyInUse")
                Case SocketError.Interrupted

                Case SocketError.NotConnected

                Case Else
                    Throw New Exception(errorCode.ToString())
            End Select
        Finally
            'Monitor.Exit(Me)
        End Try
    End Sub

    'Public Overrides Function Equals(ByVal obj As Object) As Boolean
    '    'Return MyBase.Equals(obj)
    '    'Return _ID = obj.ID
    '    'Equals = _ID = obj.ID
    '    Return _ID.Equals(obj.ID)
    'End Function

    'Public Shared Operator =(ByVal lhs As ClientInfo, ByVal rhs As Object) As Boolean
    '    Return lhs.ID = rhs.ID
    '    'Return lhs.ID.Equals(rhs.ID)
    'End Operator

    'Public Shared Operator <>(ByVal lhs As ClientInfo, ByVal rhs As Object) As Boolean
    '    Return lhs.ID <> rhs.ID
    '    'Return lhs.ID.Equals(rhs.ID)
    'End Operator

End Class



